/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.scs.ubbcluj.xml;

import edu.scs.ubbcluj.model.Database;
import edu.scs.ubbcluj.model.Table;
import edu.scs.ubbcluj.model.Attribute;
import edu.scs.ubbcluj.model.Databases;
import edu.scs.ubbcluj.model.ForeignKey;
import edu.scs.ubbcluj.view.Util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import javafx.scene.control.TreeView;

import org.jdom.*;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

public class JDom {

    private Document dom;
    private static final String XML = "base2.xml";
    private Databases databases;

    public Databases loadFromXml() {
        parseXmlFile();
        parseDocument();
        return databases;
    }

    private void parseXmlFile() {

        SAXBuilder builder = new SAXBuilder();
        try {
            dom = builder.build(XML);
        } catch (IOException | JDOMException ex) {
            ex.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    private void parseDocument() {
        databases = new Databases("Databases");
        List<Database> dataBases = new ArrayList<Database>();
        Element root = dom.getRootElement();
        List<Element> dbList = root.getChildren();
        for (Element dbelement:dbList) {
            String dbName = dbelement.getAttributeValue("dataBaseName");
            Database db = new Database(dbName);
            Element tab = dbelement.getChild("Tables");
            List<Element> tables = tab.getChildren();
            List<Table> dbTables = new ArrayList<Table>();
            for (Element tableElement:tables){
                String tableName = tableElement.getAttributeValue("tableName");
                Table table = new Table(tableName);
                Element struct = tableElement.getChild("Structure");
                List<Element> attrs = struct.getChildren();
                List<Attribute> attributes = new ArrayList<Attribute>();
                for (Element attr:attrs){
                    String attrName = attr.getAttributeValue("attributeName");
                    String type = attr.getAttributeValue("type");
                    String length = attr.getAttributeValue("length");
                    String isNull = attr.getAttributeValue("isnull");
                    Attribute attribute = new Attribute(attrName,type, Integer.parseInt(length),Boolean.parseBoolean(isNull));
                    attributes.add(attribute);
                }
                
                List<Attribute> pkAttributes = new ArrayList<Attribute>();
                Element primaryKey = tableElement.getChild("primaryKey");
                if(primaryKey != null) {
                    List<Element> pkElements = primaryKey.getChildren();
                    for (Element attr:pkElements){
                        String attrName = attr.getValue();
                        Attribute pkAttr = getAttributeByName(attributes, attrName);
                        if(pkAttr != null) {
                            pkAttributes.add(pkAttr);
                            attributes.remove(pkAttr);
                        }
                    }
                }
                
                List<ForeignKey> fkAttributes = new ArrayList<ForeignKey>();
                Element foreignKey = tableElement.getChild("foreignKeys");
                if(foreignKey != null) {
                    List<Element> fkElements = foreignKey.getChildren();
                    for (Element attr:fkElements){
                        Element fkel = attr.getChild("fkAttribute");
                        String attrName = fkel.getValue();
                        Attribute attribute = getAttributeByName(attributes, attrName);                   
                        if(attribute != null) {
                            Element refel = attr.getChild("references");
                            String refTabName = refel.getChild("refTable").getValue();
                            String refAttrName = refel.getChild("refAttribute").getValue();
                            Table t = getTableByName(dbTables, refTabName);
                            Attribute a = getAttributeByName(attributes, refAttrName);
                            fkAttributes.add(new ForeignKey(attribute, t));
                            attributes.remove(attribute);
                        }
                    }
                }
                
                Element uniqueKey = tableElement.getChild("uniqueKeys");
                if(uniqueKey != null) {
                    List<Element> ukElements = uniqueKey.getChildren();
                    for (Element attr:ukElements){
                        String attrName = attr.getValue();
                        Attribute ukAttr = getAttributeByName(attributes, attrName);
                        if(ukAttr != null) {
                            ukAttr.setUnique(true);
                        } else {
                            ForeignKey fkAttr = Util.getForeignKeyByName(fkAttributes, attrName);
                            if(fkAttr != null) {
                                fkAttr.setUnique(true);
                            }
                        }
                    }
                }
              
                Element indexEl = tableElement.getChild("IndexFiles");
                if(indexEl != null) {
                    List<Element> indexes = indexEl.getChildren();               
                    for (Element ind:indexes){
                        String indexName = ind.getAttributeValue("indexName");
                        table.setIndexFileName(indexName);
                        Element indAttrEl = ind.getChild("IndexAttributes");
                        List<Element> indexAttr = indAttrEl.getChildren();               
                        for (Element attr:indexAttr){
                            String attrName = attr.getValue();
                            Attribute ukAttr = getAttributeByName(attributes, attrName);
                            if(ukAttr != null) {
                                table.addIndexedAttributes(ukAttr);
                            } else {
                                ForeignKey fkAttr = Util.getForeignKeyByName(fkAttributes, attrName);
                                if(fkAttr != null) {
                                    table.addIndexedAttributes(fkAttr);
                                }
                            }
                        }
                    }
                }
                
                table.setAttributes(attributes);
                table.setPrimaryKeys(pkAttributes);
                table.setForeignKeys(fkAttributes);
                
                dbTables.add(table);
            }
            db.setTables(dbTables);
            dataBases.add(db);
        }
        databases.setDatabases(dataBases);
    }

    public void saveToXml(Databases databases) {

		Element root = new Element(databases.getName());
                
		for (Database db : databases.getDatabases()) {
			Element dbe = new Element("DataBase");
                        dbe.setAttribute(new org.jdom.Attribute("dataBaseName",db.getName()));
			Element tablese = new Element("Tables");
                        for (Table table:db.getTables()){
                            Element tablee = new Element("Table");
                            tablee.setAttribute(new org.jdom.Attribute("tableName", table.getName()));
                            Element struct = new Element("Structure");
                            
                            List<Attribute> unique = new ArrayList<Attribute>();
                            List<Attribute> index = table.getindexedAttributes();
                            
                            for (Attribute attr : table.getAttributes()){
                                if(attr.isUnique())
                                    unique.add(attr);
                                Element attre = new Element("Attribute");
                                attre.setAttribute(new org.jdom.Attribute("attributeName",attr.getName()));
                                attre.setAttribute(new org.jdom.Attribute("type",attr.getTip()));
                                attre.setAttribute(new org.jdom.Attribute("length",String.valueOf(attr.getLength())));
                                attre.setAttribute(new org.jdom.Attribute("isnull",String.valueOf(attr.isIsNull())));
                                struct.addContent(attre);
                            }
                            Element prKey = new Element("primaryKey");
                            for (Attribute attr : table.getPrimaryKeys()){
                                if(attr.isUnique())
                                    unique.add(attr);
                                Element attre = new Element("Attribute");
                                attre.setAttribute(new org.jdom.Attribute("attributeName",attr.getName()));
                                attre.setAttribute(new org.jdom.Attribute("type",attr.getTip()));
                                attre.setAttribute(new org.jdom.Attribute("length",String.valueOf(attr.getLength())));
                                attre.setAttribute(new org.jdom.Attribute("isnull",String.valueOf(attr.isIsNull())));
                                struct.addContent(attre);
                                Element pkAttre = new Element("pkAttribute");
                                pkAttre.setText(attr.getName());
                                prKey.addContent(pkAttre);
                            }
                            Element fKey = new Element("foreignKeys");
                            for (ForeignKey attr : table.getForeignKeys()){
                                if(attr.isUnique())
                                    unique.add(attr);
                                Element attre = new Element("Attribute");
                                attre.setAttribute(new org.jdom.Attribute("attributeName",attr.getName()));
                                attre.setAttribute(new org.jdom.Attribute("type",attr.getTip()));
                                attre.setAttribute(new org.jdom.Attribute("length",String.valueOf(attr.getLength())));
                                attre.setAttribute(new org.jdom.Attribute("isnull",String.valueOf(attr.isIsNull())));
                                struct.addContent(attre);
                                
                                Element reftab = new Element("refTable");
                                Element refattr = new Element("refAttribute");
                                
                                reftab.setText(attr.getTable().getName());
                                refattr.setText(attr.getName());
                                Element ref = new Element("references");
                                ref.addContent(reftab);
                                ref.addContent(refattr);
                                
                                Element fkAttre = new Element("fkAttribute");
                                fkAttre.setText(attr.getName());
                                
                                Element fk = new Element("foreignKey");
                                fk.addContent(fkAttre);
                                fk.addContent(ref);
                                fKey.addContent(fk);
                            }
                            Element uKey = new Element("uniqueKeys");
                            for (Attribute attr : unique){
                                Element ukAttre = new Element("UniqueAttribute");
                                ukAttre.setText(attr.getName());
                                uKey.addContent(ukAttre);
                            }
                            Element indFilesEl = new Element("IndexFiles");
                            Element indFileEl = new Element("IndexFile");
                            indFileEl.setAttribute(new org.jdom.Attribute("indexName",table.getIndexFileName()));
                            Element indAttrEl = new Element("IndexAttributes");
                            for (Attribute attr : index){
                                Element attre = new Element("IAttribute");
                                attre.setText(attr.getName());
                                indAttrEl.addContent(attre);
                            }
                            indFileEl.addContent(indAttrEl);
                            indFilesEl.addContent(indFileEl);
                            
                            tablee.addContent(struct);
                            tablee.addContent(prKey);
                            tablee.addContent(fKey);
                            tablee.addContent(uKey);
                            tablee.addContent(indFilesEl);
                            tablese.addContent(tablee);
                        }
                        dbe.addContent(tablese);
                        root.addContent(dbe);
		}

                Document doc = new Document(root);
		XMLOutputter out = new XMLOutputter();
		out.setFormat(Format.getPrettyFormat());
		try {
			out.output(doc, new FileOutputStream(new File("base2.xml")));
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}
    
    public Attribute getAttributeByName(List<Attribute> attrs, String name){
        for (Attribute attr:attrs){
            if (attr.getName().equals(name))
                return attr;
        }
        return null;
    }
    
    public Table getTableByName(List<Table> tables, String name){
        for (Table table:tables){
            if (table.getName().equals(name))
                return table;
        }
        return null;
    }
}
